package study.springcloud.gateway.support.exception;

import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
import org.springframework.cloud.gateway.support.NotFoundException;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.codec.HttpMessageWriter;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.HandlerFunction;
import org.springframework.web.reactive.function.server.RequestPredicates;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.reactive.result.view.ViewResolver;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import study.springcloud.gateway.support.utils.WebUtils;

import java.util.Collections;
import java.util.List;

/**
 * https://blog.csdn.net/weixin_43947588/article/details/106690430
 * https://blog.csdn.net/wdjnb/article/details/122066623
 */
@Slf4j
@Setter
public class GatewayExceptionHandler implements ErrorWebExceptionHandler {

    /* 消息读取器 */
    private List<HttpMessageReader<?>> messageReaders = Collections.emptyList();
    /* 消息写入器 */
    private List<HttpMessageWriter<?>> messageWriters = Collections.emptyList();
    /* 视图解析器 */
    private List<ViewResolver> viewResolvers = Collections.emptyList();

    @Override
    public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
        log.info(">>>>>> 发生异常", ex);
        //异常分类
        HttpStatus httpStatus;
        String message = "123123";
        if (ex instanceof NotFoundException) {
            httpStatus = HttpStatus.NOT_FOUND;
            message = "Service Not Found";
        } else if (ex instanceof ResponseStatusException) {
            ResponseStatusException myEx = (ResponseStatusException) ex;
            httpStatus = myEx.getStatus();
            //message = responseStatusException.getMessage();
        } else {
            httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
            message = "Internal Server Error";
        }

        //
        ServerHttpResponse response = WebUtils.getServerHttpResponse(exchange);
        if (response.isCommitted()) {
            log.info("sssssssss");
            return Mono.error(ex);
        }

        //
        final String body = message;
        ServerRequest serverRequest = ServerRequest.create(exchange, messageReaders);
        Mono<Void> mono = RouterFunctions.route(RequestPredicates.all(), new HandlerFunction<ServerResponse>() {
            @Override
            public Mono<ServerResponse> handle(ServerRequest request) {
                return ServerResponse.status(httpStatus)
                        .contentType(MediaType.APPLICATION_JSON)
                        .body(BodyInserters.fromValue(body));
            }
        }).route(serverRequest)
                .switchIfEmpty(Mono.error(ex))
                .flatMap(handlerFunction -> handlerFunction.handle(serverRequest))
//                .flatMap(new Function<HandlerFunction<ServerResponse>, Mono<?>>() {
//                    @Override
//                    public Mono<?> apply(HandlerFunction<ServerResponse> serverResponseHandlerFunction) {
//                        return Mono.empty();
//                    }
//                })
                .flatMap(serverResponse -> serverResponse.writeTo(exchange, new ResponseContext()));
        return mono;
    }

    /**
     * 参考AbstractErrorWebExceptionHandler
     */
    private Mono<ServerResponse> renderErrorResponse(int status, ServerRequest request, String body) {
        return ServerResponse.status(status)
                .contentType(MediaType.APPLICATION_JSON)
                .body(BodyInserters.fromValue(body));
    }

    /**
     * 参考 AbstractErrorWebExceptionHandler
     */
    private class ResponseContext implements ServerResponse.Context {

        private ResponseContext() {
        }

        @Override
        public List<HttpMessageWriter<?>> messageWriters() {
            return GatewayExceptionHandler.this.messageWriters;
        }

        @Override
        public List<ViewResolver> viewResolvers() {
            return GatewayExceptionHandler.this.viewResolvers;
        }
    }

    public static void main(String[] args) {
        System.out.println(System.currentTimeMillis());
    }
}
